package com.hz.cheetah.config.spring.schema;

import com.hz.cheetah.client.CheetahProxyHelper;
import javassist.*;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.w3c.dom.Element;

import java.util.UUID;

/**
 * Created by yangchuan on 16/6/15.
 */
public class CheetahBeanDefinitionParser extends AbstractSingleBeanDefinitionParser /*implements BeanDefinitionParser*/ {

    ClassPool pool = new ClassPool(true);//ClassPool.getDefault();


    @Override
    protected Class getBeanClass(Element element) {
        String interfaceName = element.getAttribute("interface");
        Class<?> interfaceClass = null;
        try {
            interfaceClass = Class.forName(interfaceName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        String serviceVersion = element.getAttribute("version");
        if(serviceVersion.equals("0.0.0")){
            serviceVersion = "";
        }
        String className =   "$JP_"
                + interfaceClass.getSimpleName()+"_" + UUID.randomUUID().toString().replaceAll("-","");
        CtClass cc = null;

        cc = pool.makeClass(className);

        try {
            CtClass superClass = pool.getCtClass(interfaceClass.getName());
            cc.addInterface(superClass);

            CtField ctField = new CtField(pool.get(CheetahProxyHelper.class.getName()),"cheetahProxyHelper",cc);
            cc.addField(ctField);
            cc.addMethod(CtNewMethod.setter("setCheetahProxyHelper", ctField));
            ctField = null;

            CtMethod[] methods = superClass.getDeclaredMethods();
            String paramStr,valuesStr;
            StringBuilder sb,values;
            for (CtMethod method : methods) {
                  Class[] ss = new Class[]{};
                sb = new StringBuilder();
                values = new StringBuilder();
                CtClass[] paramTypes =  method.getParameterTypes();
                int len = paramTypes.length+1;
                for(int i = 1;i < len; i++){
                    sb.append("$" + i + ".getClass(),");
                    values.append("$"+i+",");
                }
                paramStr = sb.toString();
                valuesStr =values.toString();
                if(paramStr.length() > 0){
                    paramStr = paramStr.substring(0,paramStr.length() - 1);
                    valuesStr = values.substring(0,values.length() - 1);
                }
                paramStr = "\n Class[] paramTypes = new Class[]{" + paramStr + "};";
                valuesStr = "\n Object[] paramValues = new Object[]{" + valuesStr + "};";

                cc.addMethod(CtNewMethod.make(
                        method.getReturnType(),
                        method.getName(),
                        paramTypes,
                        method.getExceptionTypes(),
                        "{" + paramStr + valuesStr +
                                "return (" + method.getReturnType().getSimpleName() + ")this.cheetahProxyHelper.invoke(\"" + interfaceName + "\"," +
                                "\"" + serviceVersion + "\"," +
                                "\"" + method.getName() + "\"," +
                                "paramTypes,paramValues);}",
                        cc));
            }
            paramStr = null;
            valuesStr = null;
            sb = null;
            values = null;
            cc.toClass();
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void doParse(Element element, BeanDefinitionBuilder builder) {
            builder.addPropertyReference("cheetahProxyHelper","cheetahProxyHelper");
    }
}
